<?php
/**
 * Created by PhpStorm.
 * Date: 2023/05/16
 * Time: 16:21
 * Desc: 自由生活开奖
 */

namespace app\backend\services;

use App\backend\models\LifeFreeLogModel;
use App\backend\models\LifeFreeTicketModel;
use app\backend\services\lottery\LotteryAlgorithm;
use App\common\services\BaseServices;
use App\backend\models\LifeFreeModel;
use Illuminate\Support\Facades\DB;
use Overtrue\LaravelPinyin\Facades\Pinyin;


class OpenPrizeServices extends BaseServices
{
    const TYPE_ONE = 1;
    const TYPE_TWO = 2;
    /**
     * 触发方式条件
     * trigger_method 1且  2或
     */
    const METHOD_ONE = 1;
    const METHOD_TWO = 2;

    //用户仅一次
    const UserOnlyOnce = 1;

    public function __construct()
    {
    }

    /**
     * 获取抽奖结果
     * @return void
     */
    public function open_prize($info)
    {
        //自由抽奖 开奖
        //开奖条件：1.指定时间  2.指定数量  3.同时满足两个条件，按后满足的条件执行
        $is_open = self::checkOpenCondition($info);
        if (!$is_open) {
            return self::returnError('44001','没有达成开奖条件');;
        }
        //规则：
        //1.按指定用户，或者指定中奖券选择(指定数量，少于开奖数量，则剩余数量按概率执行)
        //2.按概率执行，根据用户和系统概率
        //3.出现，一人购买所有奖券的情况，则1,2规则无效
        list($open_local, $sys_open_local) = self::byRulesOpenResult($info);

        //系统抽奖更新
        self::saveSystemLog($info,$sys_open_local);

        return self::returnSuccess('ok',['open_local'=>$open_local,'sys_open_local'=>$sys_open_local]);
    }

    /**
     * 更新系统开奖信息
     * @return void
     */
    private function saveSystemLog($info, $sys_open_local)
    {
        if ($sys_open_local == 0) return false;
        //保存系统中奖
        $logData = ['activity_id' => $info['id'], 'uid' => 0, 'ticket_num' => 1, 'content' => '中奖了', 'status' => 0];
        $ticketData = ['activity_id' => $info['id'], 'uid' => 0, 'log_id' => 0, 'local_num' => 0, 'content' => '中奖了', 'status' => 0];
        for ($i = 0; $i < count($sys_open_local);$i++) {
            //记录保存
            $logData['content'] = '用户S'.rand(0000, 9999). '中奖了';
            $log_id = LifeFreeLogModel::getInstance()->insertSave($logData);
            //奖券保存
            $ticketData['log_id'] = $log_id;
            $ticketData['local_num'] = $sys_open_local[$i];
            $ticketData['content'] = LifeFreeServices::getTicketCode($info['activity_name'], $sys_open_local[$i]);
            $res = LifeFreeTicketModel::getInstance()->insertSave($ticketData);
        }
    }

    /**
     * 根据开奖规则获取开奖结果
     * @param $info
     * @return array[]
     */
    public function byRulesOpenResult($info)
    {
        //开奖数量
        $open_num = !empty($info['draw_prize_num']) ? $info['draw_prize_num'] : 0;
        //发奖数量
        $ticket_num = !empty($info['ticket_num']) ? $info['ticket_num'] : 0;
        //已开奖
        $opened_num = 0;
        $open_data = [];//中奖信息
        $open_local = [];//中奖位置
        $need_open_num = $open_num - $opened_num;//需要开启的数量

        //单人购买开奖
        if (self::checkOnlyOneBuy($info['id'], $ticket_num, $need_open_num)) {
            self::onlyBuyOpen($info, $open_data, $open_local, $need_open_num);
        }

        //指定开奖
        if (self::checkSpecify($info['appoint_win'], $info['win_user'], $info['win_ticket'], $need_open_num)) {
            self::specifyOpen($info, $open_data, $open_local, $need_open_num);
        }

        //概率开奖
        $sys_open_local = [];
        if (!empty($need_open_num)) {
            self::chanceOpen($info, $open_data, $open_local, $sys_open_local, $need_open_num);
        }
//        echo "<pre>";
//        print_r($open_data);
        return array($open_local, $sys_open_local);
    }

    /**
     * 检查开始条件是否满足
     * @param $info
     * @return int
     */
    public function checkOpenCondition($info)
    {
        //活动开奖条件
        //是否开奖
        $is_open = 0;
        //1.奖券数量，特定时间
        if ($info['trigger_by_ticket'] == self::TYPE_ONE && $info['trigger_by_time'] == self::TYPE_ONE) {
            //开奖两种方式的关系  1.且 2.或
            $numStatus = self::triggerByTicket($info['id'], $info['open_specify_num']);
            $timeStatus = self::triggerByTime($info['open_specify_time']);
            if ($info['trigger_method'] == self::METHOD_ONE && $numStatus && $timeStatus) {
                $is_open = 1;
            } else if ($info['trigger_method'] == self::METHOD_TWO && ($numStatus || $timeStatus)) {
                $is_open = 1;
            }
        }
        //2.满足奖券数量
        if ($info['trigger_by_ticket'] == self::TYPE_ONE) {
            if (self::triggerByTicket($info['id'], $info['open_specify_num'])) {
                $is_open = 1;
            }
        }
        //3.仅满足特定时间
        if ($info['trigger_by_time'] == self::TYPE_ONE) {
            if (self::triggerByTime($info['open_specify_time'])) {
                $is_open = 1;
            }
        }
        return $is_open;
    }

    /**
     * 判断通过指定奖券--触发开奖
     * @param $activity_id
     * @param $num
     * @return bool
     */
    private function triggerByTicket($activity_id, $num)
    {
        $status = false;
        if (!empty($activity_id) && !empty($num)) {
            //获取活动购买数量
            $ticket_total = LifeFreeLogModel::getInstance()->getTicketNumSum(['activity_id' => $activity_id]);
            if ($ticket_total >= $num) {
                $status = true;
            }
        }
        return $status;
    }

    /**
     * 判断通过指定时间--触发开奖
     * @param $time
     * @return bool
     */
    private function triggerByTime($time)
    {
        $status = false;
        if (!empty($time) && $time <= time()) {
            $status = true;
        }
        return $status;
    }


    /**
     * 验证一个人购买所有奖券
     * @param $id
     * @param $ticket_num
     * @param $need_open_num
     * @return bool
     */
    private function checkOnlyOneBuy($id, $ticket_num, $need_open_num)
    {
        //当购买用户为1人，并且购买数量与发行数量一致
        if (empty($need_open_num)) return false;
        if (empty($id) || empty($ticket_num)) return false;
        $user_list = LifeFreeLogModel::getInstance()->getUserTicketNum(['activity_id' => $id]);
        if (!empty($list) && count($user_list) == 1 && $user_list['0']['total_num'] == $ticket_num) {
            return true;
        }
        return false;
    }

    /**
     * 单人购买开奖
     * @return void
     */
    private function onlyBuyOpen($info, &$open_data, &$open_local, &$need_open_num)
    {
        //随机获取用户的购买记录
        $field = ['id', 'uid', 'local_num'];
        $list = LifeFreeTicketModel::getInstance()->getRandList(['activity_id' => $info['id']], $need_open_num, $field);
        if (!empty($list)) {
            foreach ($list as $val) {
                $open_data[] = $val;
            }
            //需要开奖数量
            $need_open_num = 0;
            $open_local = array_column($open_data, 'local_num', 'local_num');
        }
    }

    /**
     * 验证指定操作
     * @param $appoint_win
     * @param $win_user
     * @param $win_ticket
     * @param $need_open_num
     * @return int
     */
    public function checkSpecify($appoint_win, $win_user, $win_ticket, $need_open_num)
    {
        $status = 0;
        if (empty($need_open_num)) return $status;
        if ($appoint_win == self::TYPE_ONE && !empty($win_user)) {
            if (!empty(self::stringToArray($win_user))) {
                $status = 1;
            }
        } elseif ($appoint_win == self::TYPE_TWO && !empty($win_ticket)) {
            if (!empty(self::stringToArray($win_ticket))) {
                $status = 2;
            }
        }
        return $status;
    }

    /**
     * 指定操作
     * @param $info
     * @param $open_data
     * @param $open_local
     * @param $need_open_num
     * @return void
     */
    private function specifyOpen($info, &$open_data, &$open_local, &$need_open_num)
    {

        $appoint_win = $info['appoint_win'];//指定类型

        switch ($appoint_win) {
            case self::TYPE_ONE:
                $win_user = self::stringToArray($info['win_user']);//用户
                //根据uid获取奖券记录
                $list = LifeFreeTicketModel::getInstance()->getList(['activity_id' => $info['id']], ['*'], ['uid' => $win_user]);
                /**
                 * //如果不去重可能会大于 总开奖数
                 * 去除重复用户？
                 */
                break;
            case self::TYPE_TWO:
                $win_ticket = self::stringToArray($info['win_ticket']);//卡券
                //根据奖券位置获取记录
                $list = LifeFreeTicketModel::getInstance()->getList(['activity_id' => $info['id']], ['*'], ['local_num' => $win_ticket]);
                break;
        }

        //获取用户的购买记录
        if (!empty($list)) {
            foreach ($list as $val) {
                $open_data[] = $val;
            }
            //需要开奖数量
            $need_open_num = $need_open_num - count($list);
            $open_local = array_column($open_data, 'local_num', 'local_num');
        }
    }

    /**
     * 概率开奖
     * @param $info
     * @param $open_data
     * @param $open_local
     * @param $sys_open_local
     * @param $need_open_num
     * @return void
     */
    private function chanceOpen($info, &$open_data, &$open_local, &$sys_open_local, &$need_open_num)
    {
        //测试用
        $need_open_num = $need_open_num + 4;

        $system_win_chance = $info['system_win_chance'];//系统中奖概率
        $user_win_chance = $info['user_win_chance'];//用户中奖概率
        //整理抽奖数组
        $arr = [
            ['id' => self::TYPE_ONE, 'pid' => 0, 'name' => 'user', 'inventory' => 0, 'chance' => $user_win_chance],
            ['id' => self::TYPE_TWO, 'pid' => 0, 'name' => 'system', 'inventory' => 0, 'chance' => $system_win_chance],
        ];
        //概率抽奖结果
        $user_win_num = 0;//用户
        $system_win_num = 0;//系统
        $Lottery = new LotteryAlgorithm($arr, 0);
        for ($i = 0; $i < $need_open_num; $i++) {
            $res_arr = $Lottery->get_prize();
            if ($res_arr['id'] == self::TYPE_TWO) {
                $system_win_num++;//在系统池中选择
            } else {
                $user_win_num++;//在用户池中选择
            }
        }

        //获取开奖结果
        //获取用户开奖结果
        if (!empty($user_win_num) && !empty($need_open_num)) {
            self::getWinUsers($info, $open_data, $open_local, $need_open_num, $user_win_num);
        }
        //获取系统开奖结果
        if (!empty($need_open_num)) {
            self::getWinSystem($info, $sys_open_local, $need_open_num);
        }
    }

    /**
     * 获取中奖用户
     * @param $info
     * @param $open_data
     * @param $open_local
     * @param $need_open_num
     * @param $user_win_num
     * @return void
     */
    public function getWinUsers($info, &$open_data, &$open_local, &$need_open_num, $user_win_num)
    {
        //获取所有奖券信息，通过随机位置来确定中奖券
        //获取除已选中，奖券之外的奖券
        $condition = ['activity_id' => $info['id']];
        $field = ['id', 'uid', 'local_num'];
        $query = DB::table(LifeFreeTicketModel::table)->select($field)->where($condition);
        if (!empty($open_local)) {
            $query->whereNotIn('local_num', $open_local);
        }
        $list = $query->get()->toarray();
        $total = count($list);
        for ($i = 0; $i < $user_win_num; $i++) {
            if ($total > 0) {
                $rand = mt_rand(1, $total);
                if (in_array($list[$rand - 1]->local_num, $open_local)) {
                    continue;
                }
                $open_local[] = $list[$rand - 1]->local_num;
                $open_data[] = $list[$rand - 1];
                unset($list[$rand - 1]);
                $list = array_values($list);
                $total--;
                $need_open_num--;
            }
        }
    }

    /**
     * 获取中奖信息
     * @param $info
     * @param $sys_open_local
     * @param $need_open_num
     * @return void
     */
    public function getWinSystem($info, &$sys_open_local, &$need_open_num)
    {
        $maxNum = LifeFreeTicketModel::getInstance()->getMaxInfo(['activity_id' => $info['id']], 'local_num');
        for ($i = 1; $i <= $need_open_num; $i++) {
            $sys_open_local[] = $maxNum + $i;
        }
        $need_open_num = 0;
    }
}
